package com.bocloud.cmp.driver.providers.vmware;

import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.bocloud.cmp.driver.providers.HostDriver;
import com.bocloud.cmp.driver.utils.AssembleTools;
import com.bocloud.cmp.model.HostModel;
import com.bocloud.cmp.model.HostOperateModel;
import com.bocloud.cmp.model.ServerModel;
import com.bocloud.common.model.BsmResult;
import com.google.common.collect.Lists;
import com.vmware.vim25.HostConnectSpec;
import com.vmware.vim25.HostSystemConnectionState;
import com.vmware.vim25.HostSystemReconnectSpec;
import com.vmware.vim25.mo.ClusterComputeResource;
import com.vmware.vim25.mo.Datacenter;
import com.vmware.vim25.mo.HostSystem;
import com.vmware.vim25.mo.InventoryNavigator;
import com.vmware.vim25.mo.ManagedEntity;
import com.vmware.vim25.mo.Task;
import com.vmware.vim25.mo.VirtualMachine;

/**
 * vmware宿主机操作接口实现类
 * 
 * @author weiwei
 *
 */
public class VmwareHostDriver extends VmwareDriver implements HostDriver {

	private static Logger logger = LoggerFactory.getLogger(VmwareHostDriver.class);

	public VmwareHostDriver() {
		super();
	}

	/**
	 * @param endpoint
	 * @param username
	 * @param password
	 */
	public VmwareHostDriver(String endpoint, String username, String password) {
		super(endpoint, username, password);
	}

	@Override
	public BsmResult create(HostOperateModel model) {// 该方法是添加主机：有两种情况：1）一种是添加到数据中心下面，作为一个standAloneHost，2）添加到数据中心下的集群中
		try {
			// 获取数据中心
			Datacenter datacenter = (Datacenter) new InventoryNavigator(this.getRootFolder()).searchManagedEntity(DC,
					model.getVdcName());
			if (null == datacenter) {
				return new BsmResult(false, "未获取到要添加主机的数据中心");
			}
			// 要添加的主机配置
			HostConnectSpec hostConnectSpec = new HostConnectSpec();
			hostConnectSpec.setForce(true);
			hostConnectSpec.setHostName(model.getHostIp());
			hostConnectSpec.setUserName(model.getUsername());
			hostConnectSpec.setPassword(model.getPassword());
			Task task = null;
			if (null != model.getClusterName()) {// 如果集群名称不为null,证明主机要添加到数据中心下的某一集群下
				// 获取集群
				ManagedEntity cluster = new InventoryNavigator(datacenter).searchManagedEntity("ClusterComputeResource",
						model.getClusterName());
				if (null != cluster) {
					if (cluster instanceof ClusterComputeResource) {
						task = ((ClusterComputeResource) cluster).addHost_Task(hostConnectSpec, true, null, null);
					}
				}
			} else {// 集群名称为null,主机只是添加到数据中心
				task = datacenter.getHostFolder().addStandaloneHost_Task(hostConnectSpec, null, true, null);
			}
			if (null != task && task.waitForTask().equals(Task.SUCCESS)) {
				// 主机添加成功之后默认是维护模式
				HostSystem host = (HostSystem) new InventoryNavigator(this.getRootFolder())
						.searchManagedEntity("HostSystem", model.getHostIp());
				HostModel hostModel = AssembleTools.getInstance().assembleVmwareHost(host);
				return new BsmResult(true, hostModel, "添加主机成功");
			} else {
				// 任务执行失败：返回执行失败的信息
				String failInfo = "";
				if (null != task && !task.waitForTask().equals(Task.SUCCESS)) {
					if (null != task.getTaskInfo().getError()) {
						failInfo = task.getTaskInfo().getError().getLocalizedMessage();
					}
				}
				return new BsmResult(false, "添加主机失败:" + failInfo);
			}
		} catch (Exception e) {
			logger.error("添加主机失败", e);
			return new BsmResult(false, "添加主机失败");
		} finally {
			this.getServiceInstance().getServerConnection().logout();
		}
	}

	@Override
	public BsmResult remove(HostOperateModel model) {
		try {
			// 获取要删除的物理机
			HostSystem host = (HostSystem) new InventoryNavigator(this.getRootFolder())
					.searchManagedEntity("HostSystem", model.getHostName());
			if (null == host) {
				return new BsmResult(false, "未找到该主机");
			}
			// 判断主机是否是在集群中
			if (null != model.getClusterName()) {// 物理机处于集群中
				// 删除物理机任务(主机必须在维护模式下:如果主机处于集群中，且处于断开状态，此时不处于维护模式也是可以删除的)
				// 获取主机当前连接状态
				HostSystemConnectionState connState = host.getSummary().getRuntime().getConnectionState();
				if (connState != null && connState.equals(HostSystemConnectionState.connected)) {// 处于连接状态、
					// 物理机位于集群中别主机处于连接状态：此时删除主机时，主机必须处于维护模式下
					if (host.getSummary().getRuntime().isInMaintenanceMode()) {
						Task task = host.destroy_Task();
						if (task.waitForTask().equals(Task.SUCCESS)) {
							return new BsmResult(true, "删除主机成功");
						} else {
							return new BsmResult(false, "删除主机失败");
						}
					} else {
						return new BsmResult(false, "主机必须处于维护模式下才能删除");
					}
				} else {
					Task task = host.destroy_Task();
					if (task.waitForTask().equals(Task.SUCCESS)) {
						return new BsmResult(true, "删除主机成功");
					} else {
						return new BsmResult(false, "删除主机失败");
					}
				}
			} else {// 物理机作为一个standAlonehost存在于数据中心下,不存在任何集群中
				Task task = host.getParent().destroy_Task();// 删除物理机任务
				if (task.waitForTask().equals(Task.SUCCESS)) {
					return new BsmResult(true, "删除主机成功");
				} else {
					return new BsmResult(false, "删除主机失败");
				}
			}
		} catch (Exception e) {
			logger.error("删除主机失败", e);
			return new BsmResult(false, "删除主机失败");
		} finally {
			this.getServiceInstance().getServerConnection().logout();
		}
	}

	@Override
	public BsmResult enterMode(HostOperateModel model) {
		try {
			// 获取要进入维护模式的物理机
			HostSystem host = (HostSystem) new InventoryNavigator(this.getRootFolder())
					.searchManagedEntity("HostSystem", model.getHostName());
			if (null == host) {
				return new BsmResult(false, "未找到该主机");
			}
			boolean mode = host.getSummary().getRuntime().isInMaintenanceMode();
			if (!mode) {
				// 主机进入维护模式任务
				Task task = host.enterMaintenanceMode(180, false, null);
				if (task.waitForTask().equals(Task.SUCCESS)) {
					return new BsmResult(true, "进入维护模式成功");
				} else {
					String failInfo = "";
					if (null != task.getTaskInfo().getError()) {
						// 返回主机进入维护模式失败的信息
						failInfo = task.getTaskInfo().getError().getLocalizedMessage();
					}
					return new BsmResult(false, "主机进入维护模式失败:" + failInfo);
				}
			} else {
				return new BsmResult(false, "主机已处于维护模式");
			}
		} catch (Exception e) {
			logger.error("进入维护模式失败", e);
			return new BsmResult(false, "进入维护模式失败");
		} finally {
			this.getServiceInstance().getServerConnection().logout();
		}
	}

	@Override
	public BsmResult exitMode(HostOperateModel model) {
		try {
			// 获取物理机
			HostSystem host = (HostSystem) new InventoryNavigator(this.getRootFolder())
					.searchManagedEntity("HostSystem", model.getHostName());
			if (null == host) {
				return new BsmResult(false, "未找到该主机");
			}
			// 获取主机模式（是否处于维护模式下）
			boolean mode = host.getSummary().getRuntime().isInMaintenanceMode();
			if (mode) {// 如果为true则证明机器处于维护模式下
				Task task = host.exitMaintenanceMode(120);// 超时时间是120秒
				// 根据任务返回结果判断主机是否退出维护模式
				if (task.waitForTask().equals(Task.SUCCESS)) {
					return new BsmResult(true, "退出维护模式");
				} else {
					return new BsmResult(false, "退出维护模式失败");
				}
			} else {
				return new BsmResult(false, "该主机未处于维护模式");
			}
		} catch (Exception e) {
			logger.error("退出维护模式失败", e);
			return new BsmResult(false, "退出维护模式失败");
		} finally {
			this.getServiceInstance().getServerConnection().logout();
		}
	}

	@Override
	public BsmResult disconn(HostOperateModel model) {
		try {
			// 获取主机
			HostSystem host = (HostSystem) new InventoryNavigator(this.getRootFolder())
					.searchManagedEntity("HostSystem", model.getHostName());
			if (null == host) {
				return new BsmResult(false, "未获取到该主机");
			}
			// 获取主机当前连接状态
			HostSystemConnectionState connState = host.getSummary().getRuntime().getConnectionState();
			if (connState.equals(HostSystemConnectionState.connected)) {
				Task task = host.disconnectHost();
				if (task.waitForTask().equals(Task.SUCCESS)) {
					return new BsmResult(true, "主机成功断开连接");
				} else {
					return new BsmResult(false, "主机断开连接失败");
				}
			} else if (connState.equals(HostSystemConnectionState.disconnected)) {
				return new BsmResult(true, "主机已处于断开连接状态");
			} else {
				return new BsmResult(false, "主机断开连接任务执行失败");
			}
		} catch (Exception e) {
			logger.error("主机断开连接失败", e);
			return new BsmResult(false, "主机断开连接失败");
		} finally {
			this.getServiceInstance().getServerConnection().logout();
		}
	}

	@Override
	public BsmResult reconn(HostOperateModel model) {
		try {
			// 获取主机
			HostSystem host = (HostSystem) new InventoryNavigator(this.getRootFolder())
					.searchManagedEntity("HostSystem", model.getHostName());
			if (null == host) {
				return new BsmResult(false, "未获取到该主机");
			}
			boolean result = false;
			String message = null;
			// 获取主机当前连接状态
			HostSystemConnectionState connState = host.getSummary().getRuntime().getConnectionState();
			if (connState.equals(HostSystemConnectionState.disconnected)) {
				// 主机重连参数设置
				HostSystemReconnectSpec reconnSpec = new HostSystemReconnectSpec();
				reconnSpec.setSyncState(true);
				// 主机重新连接任务
				Task task = host.reconnectHost_Task(null, reconnSpec);
				if (task.waitForTask().equals(Task.SUCCESS)) {
					result = true;
					message = "主机重新连接成功";
				} else {
					result = false;
					message = "主机重新连接失败";
				}
			} else if (connState.equals(HostSystemConnectionState.connected)) {
				result = true;
				message = "主机已处于连接状态";
			} else {
				result = false;
				message = "主机重新连接失败";
			}
			List<ServerModel> serverModels = Lists.newArrayList();
			if (result) {
				HostSystem hostSystem = (HostSystem) new InventoryNavigator(this.getRootFolder())
						.searchManagedEntity("HostSystem", model.getHostName());
				// 获取宿主机下的所有虚拟机
				VirtualMachine[] machines = hostSystem.getVms();// 某一个hostSystem下所有的虚拟机（取出的数量=虚拟机+模板）
				if (null != machines) {
					for (VirtualMachine machine : machines) {
						ServerModel serverModel = AssembleTools.getInstance().convertServer(machine);
						if (null != serverModel) {
							serverModels.add(serverModel);
						}
					}
				}
			}
			return new BsmResult(result, serverModels, message);
		} catch (Exception e) {
			logger.error("主机重新连接失败", e);
			return new BsmResult(false, "主机重新连接失败");
		} finally {
			this.getServiceInstance().getServerConnection().logout();
		}
	}

	@Override
	public BsmResult moveTo(HostOperateModel model) {
		// 物理机移动：1）从数据中心下移动到集群中；2）从集群中移动到数据中心下；3）从一个集群移动到另一个集群。前提是主机与集群必须处于同一个数据中心下
		// 如果主机时处于集群中，主机若要移动，主机必须处于维护模式下
		try {
			Datacenter datacenter = (Datacenter) new InventoryNavigator(this.getRootFolder()).searchManagedEntity(DC,
					model.getVdcName());
			if (null == datacenter) {
				return new BsmResult(false, "未找到该数据中心");
			}
			// 获取物理机
			List<HostSystem> hostSystems = Lists.newArrayList();
			List<String> hosts = model.getHosts();
			for (String host : hosts) {
				HostSystem hostSystem = (HostSystem) new InventoryNavigator(datacenter)
						.searchManagedEntity("HostSystem", host);
				hostSystems.add(hostSystem);
			}
			if (hostSystems.isEmpty()) {
				return new BsmResult(false, "该数据中心下不包括这些主机");
			}
			if (null == model.getClusterName()) {// 如果没有集群名称证明是移动到数据中心下面
				ManagedEntity[] entities = hostSystems.toArray(new ManagedEntity[hostSystems.size()]);
				// 移动主机到数据中心下
				Task task = datacenter.getHostFolder().moveIntoFolder_Task(entities);
				if (task.waitForTask().equals(Task.SUCCESS)) {
					return new BsmResult(true, "移动物理机成功");
				} else {
					return new BsmResult(false, "移动物理机失败");
				}
			} else {
				// 获取集群
				ManagedEntity cluster = new InventoryNavigator(datacenter).searchManagedEntity("ClusterComputeResource",
						model.getClusterName());
				if (null != cluster) {
					if (cluster instanceof ClusterComputeResource) {
						// 移动主机到集群
						HostSystem[] hostArray = hostSystems.toArray(new HostSystem[hostSystems.size()]);
						Task task = ((ClusterComputeResource) cluster).moveInto_Task(hostArray);
						if (task.waitForTask().equals(Task.SUCCESS)) {
							return new BsmResult(true, "移动物理机成功");
						} else {
							return new BsmResult(false, "移动物理机失败");
						}
					}
				}
			}
		} catch (Exception e) {
			logger.error("移动物理机失败", e);
			return new BsmResult(false, "移动物理机失败");
		} finally {
			this.getServiceInstance().getServerConnection().logout();
		}
		return new BsmResult(false, "移动物理机失败");
	}

}
